import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import mplfinance as mpf
import os

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', "WenQuanYi Micro Hei"]  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号


# 任务1：读取文件，观察数据形状，输出数据前5行，并对定量变量进行描述性分析
def task1():
    print("===== 任务1：数据读取与描述性分析 =====")
    try:
        # 读取Excel文件
        file_path = "./比亚迪后复权历史行情数据.xlsx"
        df = pd.read_excel(file_path)

        # 观察数据形状
        print(f"数据形状: {df.shape}")

        # 输出数据前5行
        print("\n数据前5行:")
        print(df.head())

        # 显示数据列名和数据类型
        print("\n数据列信息:")
        print(df.info())

        # 对定量变量进行描述性分析
        print("\n定量变量描述性统计:")
        numeric_cols = df.select_dtypes(include=['float64', 'int64']).columns
        print(df[numeric_cols].describe())

        return df
    except Exception as e:
        print(f"读取文件时出错: {e}")
        return None


# 任务2：计算变量之间的相关系数，并绘制相关系数热力图
def task2(df):
    print("\n===== 任务2：相关性分析 =====")
    try:
        # 选择定量变量进行相关性分析
        numeric_cols = df.select_dtypes(include=['float64', 'int64']).columns
        corr_matrix = df[numeric_cols].corr()

        # 打印相关系数矩阵
        print("\n相关系数矩阵:")
        print(corr_matrix)

        # 绘制相关系数热力图
        plt.figure(figsize=(10, 8))
        sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt='.2f', linewidths=0.5)
        plt.title('比亚迪股票各变量相关系数热力图')
        plt.tight_layout()
        plt.savefig('./correlation_heatmap.png', dpi=300)
        print("\n相关系数热力图已保存为 correlation_heatmap.png")
        plt.close()

    except Exception as e:
        print(f"计算相关系数时出错: {e}")


# 任务3：绘制2023年全年的收盘价时序图
def task3(df):
    print("\n===== 任务3：2023年收盘价时序图 =====")
    try:
        # 确保日期列是datetime类型
        if '日期' in df.columns:
            df['日期'] = pd.to_datetime(df['日期'])
        elif 'date' in df.columns.str.lower():
            # 尝试找到日期列
            date_col = [col for col in df.columns if 'date' in col.lower()][0]
            df[date_col] = pd.to_datetime(df[date_col])
            df = df.rename(columns={date_col: '日期'})
        else:
            print("未找到日期列")
            return

        # 筛选2023年的数据
        df_2023 = df[df['日期'].dt.year == 2023].copy()

        # 确保按日期排序
        df_2023 = df_2023.sort_values('日期')

        # 尝试找到收盘价列
        close_col = None
        for col in df.columns:
            if '收盘' in col or 'close' in col.lower():
                close_col = col
                break

        if close_col is None:
            print("未找到收盘价列")
            return

        # 绘制收盘价时序图
        plt.figure(figsize=(12, 6))
        plt.plot(df_2023['日期'], df_2023[close_col], 'b-', linewidth=2)
        plt.title('2023年比亚迪股票收盘价时序图')
        plt.xlabel('日期')
        plt.ylabel('收盘价')
        plt.grid(True, linestyle='--', alpha=0.7)
        plt.tight_layout()
        plt.savefig('./close_price_2023.png', dpi=300)
        print("\n2023年收盘价时序图已保存为 close_price_2023.png")
        plt.close()

    except Exception as e:
        print(f"绘制收盘价时序图时出错: {e}")


# 任务4：绘制2023年4月到2023年6月的K线图，并对K线图进行分析
def task4(df):
    print("\n===== 任务4：2023年4-6月K线图分析 =====")
    try:
        # 确保日期列是datetime类型
        if '日期' not in df.columns:
            print("未找到日期列")
            return

        # 筛选2023年4月到6月的数据
        start_date = '2023-04-01'
        end_date = '2023-06-30'
        df_kline = df[(df['日期'] >= start_date) & (df['日期'] <= end_date)].copy()

        if df_kline.empty:
            print("2023年4-6月期间没有数据")
            return

        # 确保按日期排序
        df_kline = df_kline.sort_values('日期')

        # 尝试找到开盘、最高、最低、收盘价列
        o_col, h_col, l_col, c_col = None, None, None, None
        for col in df.columns:
            if ('开盘' in col or 'open' in col.lower()) and o_col is None:
                o_col = col
            elif ('最高' in col or 'high' in col.lower()) and h_col is None:
                h_col = col
            elif ('最低' in col or 'low' in col.lower()) and l_col is None:
                l_col = col
            elif ('收盘' in col or 'close' in col.lower()) and c_col is None:
                c_col = col

        if None in [o_col, h_col, l_col, c_col]:
            print(f"未找到完整的K线数据列: 开盘={o_col}, 最高={h_col}, 最低={l_col}, 收盘={c_col}")
            return

        # 显示找到的列名，用于调试
        print(f"找到的K线数据列: 开盘='{o_col}', 最高='{h_col}', 最低='{l_col}', 收盘='{c_col}'")

        # 准备K线图数据 - 直接使用实际找到的列名
        kline_data = df_kline.set_index('日期')[[o_col, h_col, l_col, c_col]]

        # 重命名列以适应mplfinance
        kline_data = kline_data.rename(columns={
            o_col: 'Open',
            h_col: 'High',
            l_col: 'Low',
            c_col: 'Close'
        })

        # 绘制K线图
        mpf.plot(
            kline_data,
            type='candle',
            title='2023年4月-6月比亚迪股票K线图',
            ylabel='价格',
            style='yahoo',
            savefig='./kline_chart.png'
        )
        print("\n2023年4-6月K线图已保存为 kline_chart.png")

        # K线图分析
        print("\nK线图分析:")
        print(f"1. 分析期间: {start_date} 至 {end_date}")
        print(f"2. 期间交易日数量: {len(df_kline)}")
        print(f"3. 期初价格: {kline_data['Close'].iloc[0]:.2f}")
        print(f"4. 期末价格: {kline_data['Close'].iloc[-1]:.2f}")
        print(f"5. 期间最高价: {kline_data['High'].max():.2f}")
        print(f"6. 期间最低价: {kline_data['Low'].min():.2f}")

        # 计算涨跌幅
        pct_change = (kline_data['Close'].iloc[-1] - kline_data['Close'].iloc[0]) / kline_data['Close'].iloc[0] * 100
        print(f"7. 期间涨跌幅: {pct_change:.2f}%")

    except Exception as e:
        print(f"绘制K线图时出错: {e}")


# 主函数
if __name__ == "__main__":
    print("比亚迪股票价格走势分析与可视化")
    print("=" * 50)

    # 执行所有任务
    df = task1()
    if df is not None:
        task2(df)
        task3(df)
        task4(df)

    print("\n" + "=" * 50)
    print("分析完成！")

import pandas as pd

# 读取Excel文件
df = pd.read_excel(r'./比亚迪后复权历史行情数据.xlsx')

# 显示列名
print("=== 数据列名 ===")
print(df.columns.tolist())

# 显示数据前5行
print("\n=== 数据前5行 ===")
print(df.head())

# 显示数据信息
print("\n=== 数据信息 ===")
print(df.info())